﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using Castle.DynamicProxy;
using Wisdom.Core;

namespace Wisdom.Core
{
    /// <summary>
    /// 运用程序类
    /// </summary>
    public abstract class Application : Disposable, IApplication
    {
        #region Private Fields
        private IConfigSource _configSource;
        private ObjectContainer _objectContainer;
        private List<IInterceptor> _interceptors;
        private IBootstrapper _bootstrapper;
        
        #endregion

        #region Ctor
        /// <summary>
        /// 构造函数：初始化一个<c>Application</c> 类.
        /// </summary>
        /// <param name="configSource">用于运用程序配置的类 <see cref="Wisdom.Core.IConfigSource"/> 实例.</param>
        protected Application(IConfigSource configSource)
        {
            Initialize(configSource);
        }

        #endregion

        #region Public Properties
        /// <summary>
        /// 获得 <see cref="WisdomConfigSection"/> 类实例.
        /// </summary>
        public IConfigSource ConfigSource
        {
            get { return _configSource; }
        }
        /// <summary>
        /// 获得 <see cref="ObjectContainer"/> 类实例.
        /// </summary>
        public ObjectContainer ObjectContainer
        {
            get { return _objectContainer; }
        }
        /// <summary>
        /// 获得一个已注册到当前运用程序中指定<see cref="Castle.DynamicProxy.IInterceptor"/>类型实例的列表
        /// </summary>
        public IEnumerable<IInterceptor> Interceptors
        {
            get { return this._interceptors; }
        }
        /// <summary>
        /// 获取程序启动器
        /// </summary>
        public IBootstrapper Bootstrapper
        {
            get
            {
                return _bootstrapper;
            }
        }
        #endregion

        #region Public Events

        /// <summary>
        /// 当运用程序实始化时事件发生
        /// </summary>
        public event EventHandler<AppEventArgs> Initialized;
        public event EventHandler<AppEventArgs> Started;
        public event EventHandler<AppEventArgs> Ending;

        #endregion

        #region Public Methods
        /// <summary>
        /// 启动程序
        /// </summary>
        public virtual void Start()
        {
            this.OnInitialized();
            this.Bootstrapper.ExecuteBootstrapperTasks();
            this.OnStarted();
        }
        /// <summary>
        /// 停止程序
        /// </summary>
        public virtual void End()
        {
            this.OnEnding();
            this.Dispose();
        }
        #endregion

        #region Protected Methods
        
        protected virtual void OnStarted()
        {
            EventHandler<AppEventArgs> onStarted = this.Started;
            if (onStarted != null)
                onStarted(this, new AppEventArgs(this._configSource, this._objectContainer));

        }

        protected virtual void OnEnding()
        {
            EventHandler<AppEventArgs> onEnding = this.Ending;
            if (onEnding != null)
                onEnding(this, new AppEventArgs(this._configSource, this._objectContainer));
        }
        
        protected override void DisposeCore()
        {
            this.ObjectContainer.Dispose();
            this.Bootstrapper.Dispose();
        }

        protected abstract IBootstrapper CreateBootstrapper();

        #endregion

        #region Private Methods

        private void Initialize(IConfigSource configSource)
        {
            if (configSource == null)
                throw new ArgumentNullException("configSource");
            if (configSource.Config == null)
                throw new ConfigException("JiuZhouFrameworkConfigSection has not been defined in the ConfigSource instance.");
            if (configSource.Config.ObjectContainer == null)
                throw new ConfigException("No ObjectContainer instance has been specified in the JiuZhouFrameworkConfigSection.");
            this._configSource = configSource;
            string objectContainerProviderName = configSource.Config.ObjectContainer.Provider;
            if (string.IsNullOrEmpty(objectContainerProviderName) ||
                string.IsNullOrWhiteSpace(objectContainerProviderName))
                throw new ConfigException("The ObjectContainer provider has not been defined in the ConfigSource.");
            Type objectContainerType = Type.GetType(objectContainerProviderName);
            if (objectContainerType == null)
                throw new InfrastructureException("The ObjectContainer defined by type {0} doesn't exist.",
                                                  objectContainerProviderName);
            this._objectContainer = (ObjectContainer)Activator.CreateInstance(objectContainerType);
            if (this._configSource.Config.ObjectContainer.InitFromConfigFile)
            {
                string sectionName = this._configSource.Config.ObjectContainer.SectionName;
                if (!string.IsNullOrEmpty(sectionName) && !string.IsNullOrWhiteSpace(sectionName))
                {
                    this._objectContainer.InitializeFromConfigFile(sectionName);
                }
                else
                    throw new ConfigException(
                        "Section name for the ObjectContainer configuration should also be provided when InitFromConfigFile has been set to true.");
            }
            this._interceptors = new List<IInterceptor>();
            if (this._configSource.Config.Interception != null &&
                this._configSource.Config.Interception.Interceptors != null)
            {
                foreach (InterceptorElement interceptorElement in this._configSource.Config.Interception.Interceptors)
                {
                    Type interceptorType = Type.GetType(interceptorElement.Type);
                    if (interceptorType == null)
                        continue;
                    var interceptor = (IInterceptor)Activator.CreateInstance(interceptorType);
                    this._interceptors.Add(interceptor);
                }
            }
            this._bootstrapper = this.CreateBootstrapper();
        }

        private void OnInitialized()
        {
            EventHandler<AppEventArgs> onInitialized = this.Initialized;
            if (onInitialized != null)
                onInitialized(this, new AppEventArgs(this._configSource, this._objectContainer));
        }
        #endregion
    }
}